using System;
using System.Collections.Generic;
using UnityEngine;
using UnityEngine.Tilemaps;
using Random = UnityEngine.Random;

public class RandomDungeonUtils
{
    private static RandomDungeonUtils instance;

    public static RandomDungeonUtils Instance
    {
        get
        {
            if (instance == null)
            {
                instance = new RandomDungeonUtils();
            }

            return instance;
        }
    }

    /// <summary>
    /// 地面列表
    /// </summary>
    private List<Vector2Int> floorList = new List<Vector2Int>();

    /// <summary>
    /// 怪物可选列表
    /// </summary>
    private List<Vector3Int> monsterSeletableList = new List<Vector3Int>();

    /// <summary>
    /// 随机创建地牢
    /// </summary>
    /// <param name="dungeonDetail"></param>
    public void CreateDungeon(DungeonDetailSO dungeonDetail, Tilemap floor, Tilemap wall)
    {
        List<Vector2Int> floorList = new List<Vector2Int>();
        //1. 随机取一个点为起始点
        // int startPointY = Random.Range(0, dungeonDetail.heightTilemap);
        // int startPointX = Random.Range(0, dungeonDetail.widthTilemap);
        // Vector2Int startPos = new Vector2Int(startPointX, startPointY);
        Vector2Int startPos = new Vector2Int(0, 0);
        floorList.Add(startPos);
        for (int c = 0; c < dungeonDetail.reStartTimes; c++)
        {
            for (int s = 0; s < dungeonDetail.startTimes; s++)
            {
                Direction direction = Enum.Parse<Direction>(Random.Range(0, 4).ToString());
                Vector2Int pos = new Vector2Int(0, 0);
                switch (direction)
                {
                    case Direction.North:
                        pos = new Vector2Int(startPos.x, startPos.y + dungeonDetail.n);
                        //添加此次前进走过的所有点记作道路
                        for (int i = 1; i <= dungeonDetail.n; i++)
                        {
                            AddTile(floorList, new Vector2Int(startPos.x, startPos.y + i));
                        }

                        break;

                    case Direction.South:
                        pos = new Vector2Int(startPos.x, startPos.y - dungeonDetail.n);
                        for (int i = 1; i <= dungeonDetail.n; i++)
                        {
                            AddTile(floorList, new Vector2Int(startPos.x, startPos.y - i));
                        }

                        break;

                    case Direction.West:
                        pos = new Vector2Int(startPos.x - dungeonDetail.n, startPos.y);
                        for (int i = 1; i <= dungeonDetail.n; i++)
                        {
                            AddTile(floorList, new Vector2Int(startPos.x - i, startPos.y));
                        }

                        break;

                    case Direction.East:
                        pos = new Vector2Int(startPos.x + dungeonDetail.n, startPos.y);
                        for (int i = 1; i <= dungeonDetail.n; i++)
                        {
                            AddTile(floorList, new Vector2Int(startPos.x + i, startPos.y));
                        }

                        break;
                }

                startPos = pos;
            }

            //重新选择起始点
            int temp = Random.Range(0, floorList.Count);
            startPos = floorList[temp];
        }

        this.floorList = floorList;
        //设置路径tile
        foreach (var vector2Int in floorList)
        {
            floor.SetTile(new Vector3Int(vector2Int.x, vector2Int.y, 0), dungeonDetail.floorTile);
            //设置墙体tile

            #region 设置墙体tile

            if (!floorList.Contains(new Vector2Int(vector2Int.x - 1, vector2Int.y - 1)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y - 1), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y - 1));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y - 1), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y - 1), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x, vector2Int.y - 1)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y - 1), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y - 1));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y - 1), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y - 1), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x + 1, vector2Int.y - 1)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y - 1), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y - 1));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y - 1), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y - 1), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x - 1, vector2Int.y)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y), null);

                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x + 1, vector2Int.y)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x - 1, vector2Int.y + 1)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y + 1), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y + 1));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y + 1), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x - 1, vector2Int.y + 1), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x, vector2Int.y + 1)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y + 1), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y + 1));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y + 1), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x, vector2Int.y + 1), tileBase);
            }

            if (!floorList.Contains(new Vector2Int(vector2Int.x + 1, vector2Int.y + 1)))
            {
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y + 1), dungeonDetail.wallTile);
                var tileBase = floor.GetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y + 1));
                floor.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y + 1), null);
                wall.SetTile((Vector3Int)new Vector2Int(vector2Int.x + 1, vector2Int.y + 1), tileBase);
            }

            #endregion 设置墙体tile
        }

        //初始化玩家位置
        Vector2Int initPos = floorList[Random.Range(0, floorList.Count)];
        // GameManager.Instance.player = GameObject.Instantiate(GameResources.Instance.playerPrefab, new Vector3(initPos.x, initPos.y, 0),
        //     Quaternion.identity);
        // GameManager.Instance.player = GameObject.Instantiate(GameResources.Instance.playerPrefab,
        //     new Vector3(0.5f, -1f, 0),
        //     Quaternion.identity);
        GameManager.Instance.player = GameObject.Instantiate(GameResources.Instance.playerPrefab,
            new Vector3(0.5f,0.5f,0),
            Quaternion.identity);
        //寻找可设置怪物位置的格子
        FindTilemapForMonster(floor);
        CreateMonster(dungeonDetail);
    }

    /// <summary>
    /// 查找适合放怪物的tile
    /// </summary>
    private void FindTilemapForMonster(Tilemap floor)
    {
        foreach (Vector2Int pos in this.floorList)
        {
            Vector3Int left = new Vector3Int(pos.x - 1, pos.y, 0);
            Vector3Int right = new Vector3Int(pos.x + 1, pos.y, 0);
            Vector3Int top = new Vector3Int(pos.x, pos.y - 1, 0);
            Vector3Int bottom = new Vector3Int(pos.x, pos.y + 1, 0);
            if (floor.GetTile(left)==null && floor.GetTile(bottom)==null||
                floor.GetTile(left)==null && floor.GetTile(top)==null||
                floor.GetTile(right)==null && floor.GetTile(bottom)==null||
                floor.GetTile(right)==null && floor.GetTile(top)==null)
            {
                //不让怪物生成在玩家所在的(0,0,0)
                if (pos == Vector2Int.zero) continue;
                this.monsterSeletableList.Add(new Vector3Int(pos.x,pos.y,0));
            }
        }
    }

    private void AddTile(List<Vector2Int> floorList, Vector2Int vector2Int)
    {
        foreach (Vector2Int vector2 in floorList)
        {
            if (vector2.x == vector2Int.x && vector2.y == vector2Int.y)
            {
                return;
            }
        }

        floorList.Add(vector2Int);
    }


    /// <summary>
    /// 创建monster
    /// </summary>
    /// <param name="dungeonDetail"></param>
    public void CreateMonster(DungeonDetailSO dungeonDetail)
    {
        List<Vector3Int> selectPos = new List<Vector3Int>();
        List<int> monsterNumberList = dungeonDetail.monsterNumberList;
        for (var i = 0; i < dungeonDetail.monsterList.Count; i++)
        {
            //怪物
            GameObject monster = dungeonDetail.monsterList[i];
            for (var j = 0; j < monsterNumberList[i]; j++)
            {
                int random = Random.Range(0, monsterSeletableList.Count);
                Vector3Int monsterPos = monsterSeletableList[random];
            
                while (selectPos.Contains(monsterPos))
                {
                    monsterPos = monsterSeletableList[Random.Range(0, monsterSeletableList.Count)];
                }
            
                selectPos.Add(monsterPos);
                Debug.Log(monsterPos);
                GameObject.Instantiate(monster, new Vector3(monsterPos.x+0.5f,monsterPos.y+0.5f,0), Quaternion.identity,GameManager.Instance.monsterList);
            }
        }
    }

    enum Direction
    {
        North,
        South,
        West,
        East
    }
}